import json
import os
import uuid

import demjson
import olap.xmla.xmla as xmla
import redis
import requests
from django.http import JsonResponse
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from RelationshipAPI.settings import BASE_DIR
from app_cube.utils.connect.my_cube import MyCube
from app_cube.utils.connect.my_db import MyDB
from app_cube.utils.connect.my_win import MyWin
from app_cube.utils.data.get_datas import get_datas
from app_cube.utils.data.get_fields import get_t_or_v_fields
from app_cube.utils.data.get_table_or_view import get_measure_table_or_view
from app_cube.utils.relationship.relation import get_relation


def cube_tree(request):
    return render(request, 'app_cube/home.html')


def cube_E_R(request):
    cube_name = request.GET.get('cube_name')
    return render(request, 'app_cube/E-R.html', locals())


class MyAll:
    '''自定义所有相关类父类'''

    def __init__(self, title, id, parentId, iconClass, children, last):
        self.title = title
        self.id = id
        self.parentId = parentId
        self.iconClass = iconClass
        self.children = children
        self.last = last


# 自定义SSAS类
class MySSAS(MyAll):
    def __init__(self, title, id, parentId, iconClass, children, last, ssas):
        super(MySSAS, self).__init__(title, id, parentId, iconClass, children, last)
        self.ssas = ssas


# 自定义Cube类
class MyCubes(MyAll):
    def __init__(self, title, id, parentId, iconClass, children, last, cube):
        super(MyCubes, self).__init__(title, id, parentId, iconClass, children, last)
        self.cube = cube


# 自定义量值类
class MyMeasures(MyAll):
    def __init__(self, title, id, parentId, iconClass, children, last, measures):
        super(MyMeasures, self).__init__(title, id, parentId, iconClass, children, last)
        self.measures = measures


# 自定义维度类
class MyDimension(MyAll):
    def __init__(self, title, id, parentId, iconClass, children, last, dimension):
        super(MyDimension, self).__init__(title, id, parentId, iconClass, children, last)
        self.dimension = dimension


# 自定义关联表类
class MyTables(MyAll):
    def __init__(self, title, id, parentId, iconClass, children, last):
        super(MyTables, self).__init__(title, id, parentId, iconClass, children, last)


class CubeTreeViewAPI(APIView):
    def get(self, request, *args, **kwargs):
        try:
            # 数据源（测试阶段临时使用读文件方式）
            data_source_json = ""
            json_path = os.path.join(BASE_DIR, 'app_cube/utils/data_source/data_source.json')
            with open(json_path, 'r') as rf:
                data_source_json = json.loads(rf.read())
                rf.close()
            # 获取单个cube的关系数据
            connect = MyCube(location=data_source_json.get("host"), username=data_source_json.get("user"),
                             password=data_source_json.get("password"))
            connect = connect.connect
            # SSAS库
            if request.GET.get('catalog'):
                ssas = connect.getCatalog(request.GET.get('catalog'))
                ssas = [ssas]
            else:
                ssas = connect.getCatalogs()
            # 实例化MySSAS类对象们 id使用uuid
            my_ssas = [
                MySSAS(title=item.CATALOG_NAME, id=uuid.uuid4().hex, parentId=0, iconClass='', children=[],
                       last=False,
                       ssas=item) for
                item in ssas]
            # 实例化每个库下的多维数据集MyCubes类对象
            my_cubes = []
            for my_ssa in my_ssas:
                for item in my_ssa.ssas.getCubes():
                    my_cubes.append(
                        MyCubes(title=item.CUBE_NAME, id=uuid.uuid4().hex + 'cube', parentId=my_ssa.id, iconClass='',
                                children=[],
                                last=False, cube=item))
            # 实例化两个MyAll类对象作为每个cube的量值根、维度根
            for my_cube in my_cubes:
                my_cube.children.append(
                    MyAll(title='量值', id=uuid.uuid4().hex, parentId=my_cube.id, iconClass='', children=[],
                          last=False))
                my_cube.children.append(
                    MyAll(title='维度', id=uuid.uuid4().hex, parentId=my_cube.id, iconClass='', children=[],
                          last=False))
            # 实例化每个cube下面的量值与维度并直接放入每个cube的children里
            for my_cube in my_cubes:
                for m_d in my_cube.children:
                    if m_d.title == '量值':
                        menasures = my_cube.cube.getMeasures()
                        my_menasures = [
                            MyMeasures(title=item.MEASURE_NAME, id=uuid.uuid4().hex, parentId=m_d.id, iconClass='',
                                       children=[], last=True, measures=item) for item in menasures]
                        for my_menasure in my_menasures:
                            m_d.children.append(my_menasure)
                    elif m_d.title == '维度':
                        dimensions = my_cube.cube.getDimensions()
                        my_dimensions = [
                            MyDimension(title=item.DIMENSION_NAME, id=uuid.uuid4().hex, parentId=m_d.id,
                                        iconClass='',
                                        children=[], last=True, dimension=item) for item in dimensions]
                        for my_dimension in my_dimensions:
                            if my_dimension.title != "Measures":
                                m_d.children.append(my_dimension)
                    else:
                        pass
            # 将my_cubes追加进ssas中, 同时将表追加到cube中
            for my_ssa in my_ssas:
                for my_cube in my_cubes:
                    if my_cube.parentId == my_ssa.id:
                        my_ssa.children.append(my_cube)

            # 解析类作为响应体
            def to_json(obj):
                children = []
                for child in obj.children:
                    to_json(child)
                    children.append(child.__dict__)
                    if hasattr(child, 'cube'):
                        delattr(child, 'cube')
                    elif hasattr(child, 'measures'):
                        delattr(child, 'measures')
                    elif hasattr(child, 'dimension'):
                        delattr(child, 'dimension')
                    elif hasattr(child, 'table'):
                        delattr(child, 'table')
                obj.children = children
                return obj

            my_ssas = [to_json(i) for i in my_ssas]
            for i in my_ssas:
                delattr(i, 'ssas')
            my_ssas = [i.__dict__ for i in my_ssas]
            return JsonResponse({
                "status": {
                    "code": 200,
                    "message": "操作成功"
                },
                "data": my_ssas
            })
        except Exception as e:
            return JsonResponse({
                "status": {
                    "code": 500,
                    "message": "失败"
                },
                "error": e.__str__()
            })


class CubeERAPI(APIView):
    '''多维数据集E-R图数据API'''

    def get(self, request, *args, **kwargs):
        '''
        需要接受数据源id，cube名称
        :param request:
        :param args:
        :param kwargs:
        :return:
        '''
        try:
            # 获取GET参数
            params = request.GET.dict()
            cube_name = params.get("cube_name")
            # 数据源（测试阶段临时使用读文件方式）
            data_source_json = ""
            json_path = os.path.join(BASE_DIR, 'app_cube/utils/data_source/data_source.json')
            with open(json_path, 'r') as rf:
                data_source_json = json.loads(rf.read())
                rf.close()
            # 获取单个cube的关系数据
            cube_conn = MyCube(location=data_source_json.get("host"), username=data_source_json.get("user"),
                               password=data_source_json.get("password"))
            catalog = cube_conn.get_catalog(data_source_json.get('data_base')).get(data_source_json.get('data_base'))
            cube = cube_conn.get_cube(catalog, cube_name).get(cube_name)
            measures = [list(measure.values())[0] for measure in cube_conn.get_measure(cube)]
            # 获取每一个量值关系
            remote = data_source_json.get("remote")
            win_conn = MyWin(host=remote.get("host"), username=remote.get("user"), password=remote.get("password"))
            file_path = data_source_json.get("remote").get("file_path")
            relations = []  # 临时存储关系
            for measure in measures:
                table = get_measure_table_or_view(cube, measure, win_conn, file_path)
                if table != {}:
                    relation = get_relation(list(table.values())[0], win_conn, file_path)
                    relations.append(relation)
            # 获取每一个量值表或视图与维度关系
            measure_list = [list(relation.keys())[0] for relation in relations]
            measure_list = list(set(measure_list))
            dim_list = []
            for relation in relations:
                meas_name = list(relation.keys())[0]
                for dim in relation.get(meas_name):
                    dim_list.append(dim)
            dim_list = list(set(dim_list))
            er_data = []  # 临时存储当前cube展示E-R图所有数据
            # 连接Cube数据源
            cube_source = data_source_json.get("source")
            db_conn = MyDB(classify=cube_source.get("classify"), host=cube_source.get("host"),
                           port=cube_source.get("port"), user=cube_source.get("user"),
                           password=cube_source.get("password"),
                           database=cube_source.get("data_base"))
            for table in measure_list + dim_list:
                # 获取每一个表或视图字段
                fields = get_t_or_v_fields(table_name=table, path=file_path, win_conn=win_conn, db_conn=db_conn)
                items = []
                for field in fields:
                    item = {
                        'name': field,
                        'iskey': False,
                    }
                    items.append(item)
                table_dict = {
                    "key": table,
                    "items": items
                }
                er_data.append(table_dict)
            # E-R图连接线数据
            conn_line = []
            for relation in relations:
                meas_name = list(relation.keys())[0]
                for dim in relation.get(meas_name):
                    line_dict = {
                        "from": meas_name,
                        "to": dim,
                    }
                    conn_line.append(line_dict)
            # 去重
            conn_line_data = []
            for item in conn_line:
                if item not in conn_line_data:
                    conn_line_data.append(item)

            # 关闭数据库连接
            db_conn.close()
            return Response(data={"relation": er_data, "line": conn_line_data})
        except Exception as e:
            raise e


def browser_data(request):
    if request.method == 'GET':
        try:
            table_name = request.GET.get("table_name")
            # 建立数据库连接
            # 数据源（测试阶段临时使用读文件方式）
            data_source_json = ""
            json_path = os.path.join(BASE_DIR, 'app_cube/utils/data_source/data_source.json')
            with open(json_path, 'r') as rf:
                data_source_json = json.loads(rf.read())
                rf.close()
            data_source = data_source_json.get('source')
            db_conn = MyDB(classify=data_source.get('classify'), host=data_source.get('host'),
                           port=data_source.get('port'), user=data_source.get('user'),
                           password=data_source.get('password'), database=data_source.get('data_base'))
            remote = data_source_json.get('remote')
            win_conn = MyWin(host=remote.get('host'), username=remote.get('user'), password=remote.get('password'))
            # 获取字段名
            # table_fields = db_conn.get_field_name("select * from {}".format(table_name))
            table_fields = get_t_or_v_fields(table_name=table_name, path=data_source_json.get('remote').get('file_path'),
                                             win_conn=win_conn, db_conn=db_conn)

            db_conn.close()
            col = []
            # 配置表头
            for table_field in table_fields:
                col.append({"field": table_field, "title": table_field})
            cols = [col]
            return render(request, 'app_cube/browser_data.html', locals())
        except Exception as e:
            return render(request, '500.html')
    else:
        try:
            table_name = request.POST.get("table_name")
            # 建立数据库连接
            # 数据源（测试阶段临时使用读文件方式）
            data_source_json = ""
            json_path = os.path.join(BASE_DIR, 'app_cube/utils/data_source/data_source.json')
            with open(json_path, 'r') as rf:
                data_source_json = json.loads(rf.read())
                rf.close()
            data_source = data_source_json.get('source')
            db_conn = MyDB(classify=data_source.get('classify'), host=data_source.get('host'),
                           port=data_source.get('port'), user=data_source.get('user'),
                           password=data_source.get('password'), database=data_source.get('data_base'))
            remote = data_source_json.get('remote')
            win_conn = MyWin(host=remote.get('host'), username=remote.get('user'), password=remote.get('password'))
            # 获取数据
            datas = get_datas(table_name=table_name, path=data_source_json.get('remote').get('file_path'), win_conn=win_conn,
                              db_conn=db_conn)
            db_conn.close()
            # 返回数据
            return JsonResponse({"data": datas})
        except Exception as e:
            return JsonResponse({"data": [e]})


def relation_E_R(request):
    if request.method == 'GET':
        try:
            cube_name = request.GET.get('cube_name')
            node_name = request.GET.get('node_name')  # 当前节点名
            response = requests.get("http://127.0.0.1:8000/cube_api/E-R-API/?cube_name={}".format(cube_name))
            relation_datas = response.json()
            # 重新生成关系数据
            lines = relation_datas.get('line')
            line_list = []  # 临时存储连线
            node_name_list = []
            for line in lines:
                if node_name == line.get('from') or node_name == line.get('to'):
                    line_list.append(line)
                    node_name_list.append(line.get('from'))
                    node_name_list.append(line.get('to'))
            node_name_list = list(set(node_name_list))  # 去除重复节点名
            # 关联节点
            node_datas = relation_datas.get('relation')
            node_list = []
            for node in node_datas:
                if node.get('key') in node_name_list:
                    node_list.append(node)
            return JsonResponse({'relation': node_list, 'line': line_list})
        except Exception as e:
            raise e
